package net.sf.google.talk.eclipse.views;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.google.talk.eclipse.EclipsePlugin;
import net.sf.google.talk.eclipse.preferences.GTalkPreferencePage;
import net.sf.google.talk.eclipse.swt.Conversation;

import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterGroup;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.RosterPacket.ItemType;
import org.jivesoftware.smackx.filetransfer.FileTransferListener;
import org.jivesoftware.smackx.filetransfer.FileTransferManager;
import org.jivesoftware.smackx.filetransfer.FileTransferRequest;
import org.jivesoftware.smackx.filetransfer.IncomingFileTransfer;

/**
 * @deprecated the new view UsersView
 * @author mgriffa
 */
@Deprecated
public class GTalkView extends ViewPart {
	private Roster roster;

	private Label infoLabel;

	private XMPPConnection connection;

	private Tree tree;

	private String username;

	private String password;

	private final List<RosterEntry> entriesList = new ArrayList<RosterEntry>();

	private final Action newLoginAction = new Action() {
		{
			setText("new login");
		}

		@Override
		public void run() {
			reconnect(true);
		}
	};

	private final Action disconnectAction = new Action() {
		{
			setText("disconnect");
		}

		@Override
		public void run() {
			if (connection != null) {
				connection.disconnect();
			}
		}
	};

	private final Action reconnectAction = new Action() {
		{
			setText("reconnect");
		}

		@Override
		public void run() {
			reconnect();
		}
	};

	private final PacketFilter newChatFilter = new PacketTypeFilter(Message.class);

	private final PacketFilter newPresenceFilter = new PacketTypeFilter(Presence.class);

	private final PacketListener newChatListener = new PacketListener() {
		public void processPacket(Packet arg0) {
			System.out.println("Chat packet received: " + arg0);
			final Message n = (Message) arg0;
			if (n.getType().equals(Message.Type.chat) || n.getType().equals(Message.Type.normal)) {
				System.out.println("crear chat o dispatchear a existente");
				getSite().getShell().getDisplay().asyncExec(new Runnable() {

					public void run() {
						IViewPart part;
						part = getSite().getPage().findView("net.sf.google.talk.eclipse.views.GTalkConversationView");
						//part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView("net.sf.google.talk.eclipse.views.GTalkConversationView");
						GTalkConversationView c = (GTalkConversationView) part.getAdapter(GTalkConversationView.class);
						Conversation conv = c.getConversation(n.getFrom());
						//                            if (conv == null) {
						//                            	conv = (Conversation) part.getAdapter(Conversation.class);
						//                            }
						createChat(conv, n.getFrom());
						c.dispatch(n);
					}
				});
			}
		}
	};

	private final PacketListener newPresenceListener = new PacketListener() {
		public void processPacket(Packet arg0) {
			Presence n = (Presence) arg0;
			processPresence(n);
		}
	};

	private final ILog log = EclipsePlugin.getDefault().getLog();

	public GTalkView() {
	}

	private void fillLocalToolBar(final IToolBarManager manager) {
		manager.add(newLoginAction);
		manager.add(reconnectAction);
		manager.add(disconnectAction);
	}

	private void contributeToActionBars() {
		final IActionBars bars = getViewSite().getActionBars();
		//      fillLocalPullDown(bars.getMenuManager());
		fillLocalToolBar(bars.getToolBarManager());
	}

	@Override
	public void createPartControl(final Composite parent) {
		parent.setLayout(new GridLayout(1, true));
		tree = new Tree(parent, SWT.NONE);
		tree.setLayoutData(new GridData(GridData.FILL_BOTH));
		infoLabel = new Label(parent, SWT.NONE);
		infoLabel.setText("Double Click a user to initiate chat");
		//            connection = new XMPPConnection("google.com");
		reconnect();
		//            con.createChat("maryjane@gmail.com")
		//            .sendMessage("Howdy!");

		tree.addMouseListener(new MouseListener() {
			public void mouseDoubleClick(final MouseEvent e) {
				onDoubleClick();

			}

			public void mouseDown(final MouseEvent e) {
			}

			public void mouseUp(final MouseEvent e) {
			}
		});
		tree.addSelectionListener(new SelectionListener() {
			public void widgetDefaultSelected(final SelectionEvent e) {
				widgetSelected(e);
			}

			public void widgetSelected(final SelectionEvent e) {
				onTreeSelected(e);
			}
		});
		contributeToActionBars();
	}

	/**
	 * Executed when an item on the users tree is selected
	 * @param e the event 
	 */
	protected void onTreeSelected(final SelectionEvent e) {
		System.out.println("onTreeSelected: " + e);
		final TreeItem[] sel = tree.getSelection();
		if (sel != null && sel.length > 0) {
			final TreeItem item = sel[0];
			final Object data = item.getData();
			if (data instanceof RosterEntry) {
				final RosterEntry re = (RosterEntry) data;
				final String txt = re.getName() + ", " + re.getUser() + ", " + re.getStatus() + ", " + re.getType();
				this.infoLabel.setText(txt);
				System.out.println("info updated: " + txt);
			} else {
				System.out.println("No data on TreeItem");
			}
		} else {
			System.out.println("Selection empty");
		}
	}

	@Override
	public void setFocus() {
		System.out.println("GTalkView.setFocus()");
	}

	protected void reconnect() {
		reconnect(false);
	}

	protected void reconnect(final boolean promptNew) {
		try {
			infoLabel.setText("");
			setUserInfo(promptNew);

			tree.removeAll();
			connection = new XMPPConnection("gmail.com");
			connection.addPacketListener(newChatListener, newChatFilter);

			connection.addPacketListener(newPresenceListener, newPresenceFilter);
			XMPPConnection.DEBUG_ENABLED = true;

			connection.login(username, password);
			roster = connection.getRoster();
			final TreeItem root = new TreeItem(tree, SWT.NONE);
			root.setText("Google Talk");

			final Collection<RosterEntry> enties = roster.getEntries();

			final Map<String, TreeItem> treeItemGroups = new HashMap<String, TreeItem>();

			offlineUsers = new TreeItem(root, SWT.NONE);
			offlineUsers.setText("none");

			for (final RosterEntry entry : enties) {
				for (final RosterGroup group : entry.getGroups()) {
					final String groupName = "" + group.getName();
					TreeItem treeItemGroup = treeItemGroups.get(groupName);
					if (treeItemGroup == null) {
						treeItemGroup = new TreeItem(root, SWT.NONE);
						treeItemGroup.setText(groupName);
						treeItemGroups.put(groupName, treeItemGroup);
					}
					addUser(entry, treeItemGroup);
				}
				//				} else {
				//					addUser(entry, root);
				//				}
			}

			// Add filetransfer listener
			final FileTransferManager ftm = new FileTransferManager(connection);
			ftm.addFileTransferListener(new FileTransferListener() {

				public void fileTransferRequest(final FileTransferRequest ftr) {
					final IncomingFileTransfer ift = ftr.accept();
					final String incomingFileName = ftr.getFileName();
					// the file that incoming
					final File incomingFile = new File("/tmp/" + incomingFileName);
					try {
						// use of IncomingFileTransfer#recieveFile(File)
						ift.recieveFile(incomingFile);
						// TODO: how to monitor transfer as described in javadoc???
					} catch (final XMPPException e) {
						System.out.println("Error: could not receive file!");
						e.printStackTrace();
					}
				}

			});

		} catch (final Exception e) {
			log.log(new Status(Status.ERROR, EclipsePlugin.ID, Status.OK, "Error connecting to server ", e));
			infoLabel.setText("Error connecting: " + e);
			MessageDialog.openError(getSite().getShell(), "Error connecting", "Detail: " + e);
		}

	}

	private TreeItem offlineUsers;

	private void addUser(final RosterEntry entry, TreeItem treeItemGroup) {
		final ItemType type = entry.getType();
		String name = entry.getName();
		if (name == null) {
			name = entry.getUser();
		}
		name = name + " [" + type + "]";
		if (type.equals(ItemType.none)) {
			treeItemGroup = offlineUsers;
		}
		final TreeItem treeItemUser = new TreeItem(treeItemGroup, SWT.NONE);
		treeItemUser.setText(name);
		treeItemUser.setData(entry);
		entriesList.add(entry);
	}

	private void setUserInfo(boolean promptNew) {
		final IPreferenceStore store = EclipsePlugin.getDefault().getPreferenceStore();
		if (store.contains(GTalkPreferencePage.USERNAME) && !promptNew) {
			username = store.getString(GTalkPreferencePage.USERNAME);
			password = store.getString(GTalkPreferencePage.PASSWORD);
		} else {
			final LoginDialog ld = new LoginDialog(getSite().getShell());
			final int rc = ld.open();
			if (rc == Window.OK) {
				username = ld.getUsername();
				password = ld.getPassword();
				//                if (ld.isSaveValues()) {
				//                    store.setValue(GTalkPreferencePage.USERNAME, username);
				//                    store.setValue(GTalkPreferencePage.PASSWORD, password);
				//                }
			}
		}
	}

	/**
	 * update the users view with the presence packet
	 * @param n the presence packet received
	 */
	private void processPresence(final Presence n) {
		System.out.println("Presence packet received: " + n);
		System.out.println("From: " + n.getFrom());
		System.out.println("Status: " + n.getStatus());
		System.out.println("Type: " + n.getType());
		for (final RosterEntry e : entriesList) {
			System.out.println("e.user " + e.getUser());
			System.out.println("n.from " + n.getFrom());
			if (n.getFrom().startsWith(e.getUser())) {
				// TODO update status for this user
			}
		}
	}

	/**
	 * Create a chat for the given user
	 */
	private void createChat(final Conversation c, final String user) {
		final Chat chat = connection.getChatManager().createChat(user, c);
		c.setUser(connection.getUser());
		c.setChat(chat);
	}

	private void onDoubleClick() {
		final RosterEntry o = (RosterEntry) tree.getSelection()[0].getData();
		// TODO send this chat to the conversation view
		try {
			final IViewPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView("net.sf.google.talk.eclipse.views.GTalkConversationView");
			final Conversation c = (Conversation) part.getAdapter(Conversation.class);
			final String user = o.getUser();
			createChat(c, user);
		} catch (final PartInitException ex) {
			ex.printStackTrace();
			log.log(new Status(Status.ERROR, EclipsePlugin.ID, Status.OK, "Error creating conversation", ex));
		}
	}

}